home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume90 / unix / cpp / part03 < prev    next >
Encoding:
Internet Message Format  |  1990-01-18  |  45.7 KB

  1. Path: xanth!cs.odu.edu!Amiga-Request
  2. From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v90i024: cpp - a c preprocessor with some ANSI features, Part03/05
  5. Message-ID: <11032@xanth.cs.odu.edu>
  6. Date: 18 Jan 90 00:19:37 GMT
  7. Sender: tadguy@cs.odu.edu
  8. Reply-To: Olaf 'Rhialto' Seibert <U211344@HNYKUN11.BITNET>
  9. Lines: 1666
  10. Approved: tadguy@cs.odu.edu (Tad Guy)
  11.  
  12. Submitted-by: Olaf 'Rhialto' Seibert <U211344@HNYKUN11.BITNET>
  13. Posting-number: Volume 90, Issue 024
  14. Archive-name: unix/cpp/part03
  15.  
  16. #!/bin/sh
  17. # This is a shell archive.  Remove anything before this line, then unpack
  18. # it by saving it into a file and typing "sh file".  To overwrite existing
  19. # files, type "sh file -c".  You can also feed this as standard input via
  20. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  21. # will see the following message at the end:
  22. #        "End of archive 3 (of 5)."
  23. # Contents:  Cpp4.c cpp5.c
  24. # Wrapped by tadguy@xanth on Wed Jan 17 19:17:35 1990
  25. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  26. if test -f 'Cpp4.c' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'Cpp4.c'\"
  28. else
  29. echo shar: Extracting \"'Cpp4.c'\" \(19642 characters\)
  30. sed "s/^X//" >'Cpp4.c' <<'END_OF_FILE'
  31. X/*
  32. X *                C P P 4 . C
  33. X *        M a c r o  D e f i n i t i o n s
  34. X *
  35. X * Edit History
  36. X * 31-Aug-84    MM    USENET net.sources release
  37. X * 04-Oct-84    MM    __LINE__ and __FILE__ must call ungetstring()
  38. X *            so they work correctly with token concatenation.
  39. X *            Added string formal recognition.
  40. X * 25-Oct-84    MM    "Short-circuit" evaluate #if's so that we
  41. X *            don't print unnecessary error messages for
  42. X *            #if !defined(FOO) && FOO != 0 && 10 / FOO ...
  43. X * 31-Oct-84    ado/MM    Added token concatenation
  44. X *  6-Nov-84    MM    Split off eval stuff
  45. X * 21-Oct-85    RMS    Rename `token' to `tokenbuf'.
  46. X *            In doundef, don't complain if arg already not defined.
  47. X * 14-Mar-86    FNF    Incorporate macro based C debugging package.
  48. X *            Port to Commodore AMIGA.
  49. X * 21-Aug-88    Ois    Changed concatenation operator to ##. Changed hand-
  50. X *            ling of tokens following ##. Added new meaning of #.
  51. X */
  52. X
  53. X#include    <stdio.h>
  54. X#include    <ctype.h>
  55. X#include    "cppdef.h"
  56. X#include    "cpp.h"
  57. X/*
  58. X * parm[], parmp, and parlist[] are used to store #define() argument
  59. X * lists.  nargs contains the actual number of parameters stored.
  60. X */
  61. Xstatic char    parm[NPARMWORK + 1];    /* define param work buffer    */
  62. Xstatic char    *parmp;         /* Free space in parm        */
  63. Xstatic char    *parlist[LASTPARM];    /* -> start of each parameter    */
  64. Xstatic int    nargs;            /* Parameters for this macro    */
  65. X
  66. Xdodefine()
  67. X/*
  68. X * Called from control when a #define is scanned.  This module
  69. X * parses formal parameters and the replacement string.  When
  70. X * the formal parameter name is encountered in the replacement
  71. X * string, it is replaced by a character in the range 128 to
  72. X * 128+NPARAM (this allows up to 32 parameters within the
  73. X * Dec Multinational range).  If cpp is ported to an EBCDIC
  74. X * machine, you will have to make other arrangements.
  75. X *
  76. X * There is some special case code to distinguish
  77. X *    #define foo    bar
  78. X * from #define foo()   bar
  79. X *
  80. X * Also, we make sure that
  81. X *    #define foo    foo
  82. X * expands to "foo" but doesn't put cpp into an infinite loop.
  83. X *
  84. X * A warning message is printed if you redefine a symbol to a
  85. X * different text.  I.e,
  86. X *    #define foo    123
  87. X *    #define foo    123
  88. X * is ok, but
  89. X *    #define foo    123
  90. X *    #define foo    +123
  91. X * is not.
  92. X *
  93. X * The following subroutines are called from define():
  94. X * checkparm    called when a token is scanned.  It checks through the
  95. X *        array of formal parameters.  If a match is found, the
  96. X *        token is replaced by a control byte which will be used
  97. X *        to locate the parameter when the macro is expanded.
  98. X * textput    puts a string in the macro work area (parm[]), updating
  99. X *        parmp to point to the first free byte in parm[].
  100. X *        textput() tests for work buffer overflow.
  101. X * charput    puts a single character in the macro work area (parm[])
  102. X *        in a manner analogous to textput().
  103. X */
  104. X{
  105. X    register int        c;
  106. X    register DEFBUF     *dp;        /* -> new definition    */
  107. X    int            isredefine;    /* TRUE if redefined    */
  108. X    char            *old;        /* Remember redefined    */
  109. X#if OK_CONCAT
  110. X    register int        quoting;    /* Remember we saw a #    */
  111. X#endif
  112. X    extern int        save();         /* Save char in work[]  */
  113. X
  114. X    DBUG_ENTER ("dodefine");
  115. X    if (type[(c = skipws())] != LET)
  116. X        goto bad_define;
  117. X    isredefine = FALSE;            /* Set if redefining    */
  118. X    if ((dp = lookid(c)) == NULL)           /* If not known now     */
  119. X        dp = defendel(tokenbuf, FALSE);     /* Save the name        */
  120. X    else {                    /* It's known:          */
  121. X        isredefine = TRUE;            /* Remember this fact    */
  122. X        old = dp->repl;            /* Remember replacement */
  123. X        dp->repl = NULL;            /* No replacement now    */
  124. X    }
  125. X    parlist[0] = parmp = parm;        /* Setup parm buffer    */
  126. X    if ((c = get()) == '(') {               /* With arguments?      */
  127. X        nargs = 0;                /* Init formals counter */
  128. X        do {                /* Collect formal parms */
  129. X        if (nargs >= LASTPARM)
  130. X            cfatal("Too many arguments for macro", NULLST);
  131. X        else if ((c = skipws()) == ')')
  132. X            break;            /* Got them all     */
  133. X        else if (type[c] != LET)        /* Bad formal syntax    */
  134. X            goto bad_define;
  135. X        scanid(c);                      /* Get the formal param */
  136. X        parlist[nargs++] = parmp;    /* Save its start    */
  137. X        textput(tokenbuf);              /* Save text in parm[]  */
  138. X        } while ((c = skipws()) == ',');    /* Get another argument */
  139. X        if (c != ')')                       /* Must end at )        */
  140. X        goto bad_define;
  141. X        c = ' ';                            /* Will skip to body    */
  142. X    }
  143. X    else {
  144. X        /*
  145. X         * DEF_NOARGS is needed to distinguish between
  146. X         * "#define foo" and "#define foo()".
  147. X         */
  148. X        nargs = DEF_NOARGS;         /* No () parameters     */
  149. X    }
  150. X    if (type[c] == SPA)                     /* At whitespace?       */
  151. X        c = skipws();                       /* Not any more.        */
  152. X    workp = work;                /* Replacement put here */
  153. X    inmacro = TRUE;             /* Keep \<newline> now    */
  154. X    quoting = 0;                /* No # seen yet.    */
  155. X    while (c != EOF_CHAR && c != '\n') {    /* Compile macro body   */
  156. X#if OK_CONCAT
  157. X        if (c == '#') {                     /* Token concatenation? */
  158. X        if ((c = get()) != '#') {       /* No, not really       */
  159. X            quoting = 1;        /* Maybe quoting op.    */
  160. X            continue;
  161. X        }
  162. X        while (workp > work && type[workp[-1]] == SPA)
  163. X            --workp;            /* Erase leading spaces */
  164. X        save(TOK_SEP);                  /* Stuff a delimiter    */
  165. X        c = skipws();                   /* Eat whitespace       */
  166. X#if 0
  167. X        if (type[c] == LET)             /* Another token here?  */
  168. X            ;                /* Stuff it normally    */
  169. X        else if (type[c] == DIG) {      /* Digit string after?  */
  170. X            while (type[c] == DIG) {    /* Stuff the digits     */
  171. X            save(c);                /* Note
  172. X            c = get();
  173. X            }
  174. X            save(TOK_SEP);              /* Delimit 2nd token    */
  175. X        }
  176. X        else {
  177. X            ciwarn("Strange character after ## (%d.)", c);
  178. X        }
  179. X#endif
  180. X        continue;
  181. X        }
  182. X#endif
  183. X        switch (type[c]) {
  184. X        case LET:
  185. X#if OK_CONCAT
  186. X        checkparm(c, dp, quoting);      /* Might be a formal    */
  187. X#else
  188. X        checkparm(c, dp);               /* Might be a formal    */
  189. X#endif
  190. X        break;
  191. X
  192. X        case DIG:                /* Number in mac. body    */
  193. X        case DOT:                /* Maybe a float number */
  194. X        scannumber(c, save);            /* Scan it off          */
  195. X        break;
  196. X
  197. X        case QUO:                /* String in mac. body    */
  198. X#if STRING_FORMAL
  199. X        stparmscan(c, dp);              /* Do string magic      */
  200. X#else
  201. X        stparmscan(c);
  202. X#endif
  203. X        break;
  204. X
  205. X        case BSH:                /* Backslash        */
  206. X        save('\\');
  207. X        if ((c = get()) == '\n')
  208. X            wrongline = TRUE;
  209. X        save(c);
  210. X        break;
  211. X
  212. X        case SPA:                /* Absorb whitespace    */
  213. X        /*
  214. X         * Note: the "end of comment" marker is passed on
  215. X         * to allow comments to separate tokens.
  216. X         */
  217. X        if (workp[-1] == ' ')           /* Absorb multiple      */
  218. X            break;            /* spaces        */
  219. X        else if (c == '\t')
  220. X            c = ' ';                    /* Normalize tabs       */
  221. X        /* Fall through to store character            */
  222. X        default:                /* Other character    */
  223. X        save(c);
  224. X        break;
  225. X        }
  226. X        c = get();
  227. X        quoting = 0;            /* Only when immediately*/
  228. X                        /* preceding a formal    */
  229. X    }
  230. X    inmacro = FALSE;            /* Stop newline hack    */
  231. X    unget();                                /* For control check    */
  232. X    if (workp > work && workp[-1] == ' ')   /* Drop trailing blank  */
  233. X        workp--;
  234. X    *workp = EOS;                /* Terminate work    */
  235. X    dp->repl = savestring(work);            /* Save the string      */
  236. X    dp->nargs = nargs;            /* Save arg count    */
  237. X#if DEBUG
  238. X    if (debug)
  239. X        dumpadef("macro definition", dp);
  240. X#endif
  241. X    if (isredefine) {                       /* Error if redefined   */
  242. X        if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl))
  243. X         || (old == NULL && dp->repl != NULL)
  244. X         || (old != NULL && dp->repl == NULL)) {
  245. X        cerror("Redefining defined variable \"%s\"", dp->name);
  246. X        }
  247. X        if (old != NULL)                    /* We don't need the    */
  248. X        free(old);                      /* old definition now.  */
  249. X    }
  250. X    DBUG_VOID_RETURN;
  251. X
  252. Xbad_define:
  253. X    cerror("#define syntax error", NULLST);
  254. X    inmacro = FALSE;            /* Stop <newline> hack    */
  255. X    DBUG_VOID_RETURN;
  256. X}
  257. X
  258. Xcheckparm(c, dp, quoting)
  259. Xregister int    c;
  260. XDEFBUF        *dp;
  261. Xint        quoting;            /* Preceded by a # ?    */
  262. X/*
  263. X * Replace this param if it's defined.  Note that the macro name is a
  264. X * possible replacement token.    We stuff DEF_MAGIC in front of the token
  265. X * which is treated as a LETTER by the token scanner and eaten by
  266. X * the output routine.    This prevents the macro expander from
  267. X * looping if someone writes "#define foo foo".
  268. X */
  269. X{
  270. X    register int        i;
  271. X    register char        *cp;
  272. X
  273. X    DBUG_ENTER ("checkparm");
  274. X    scanid(c);                              /* Get parm to tokenbuf */
  275. X    for (i = 0; i < nargs; i++) {           /* For each argument    */
  276. X        if (streq(parlist[i], tokenbuf)) {  /* If it's known        */
  277. X#if OK_CONCAT
  278. X        if (quoting)                    /* Special handling of  */
  279. X            save(QUOTE_PARM);           /* #formal inside defn  */
  280. X#endif
  281. X        save(i + MAC_PARM);             /* Save a magic cookie  */
  282. X        DBUG_VOID_RETURN;        /* And exit the search    */
  283. X        }
  284. X    }
  285. X    if (streq(dp->name, tokenbuf))          /* Macro name in body?  */
  286. X        save(DEF_MAGIC);                    /* Save magic marker    */
  287. X    for (cp = tokenbuf; *cp != EOS;)        /* And save             */
  288. X        save(*cp++);                        /* The token itself     */
  289. X    DBUG_VOID_RETURN;
  290. X}
  291. X
  292. X#if STRING_FORMAL
  293. Xstparmscan(delim, dp)
  294. Xint        delim;
  295. Xregister DEFBUF *dp;
  296. X/*
  297. X * Scan the string (starting with the given delimiter).
  298. X * The token is replaced if it is the only text in this string or
  299. X * character constant.    The algorithm follows checkparm() above.
  300. X * Note that scanstring() has approved of the string.
  301. X */
  302. X{
  303. X    register int        c;
  304. X
  305. X    DBUG_ENTER ("stparmscan");
  306. X    /*
  307. X     * Warning -- this code hasn't been tested for a while.
  308. X     * It exists only to preserve compatibility with earlier
  309. X     * implementations of cpp.  It is not part of the Draft
  310. X     * ANSI Standard C language.
  311. X     */
  312. X    save(delim);
  313. X    instring = TRUE;
  314. X    while ((c = get()) != delim
  315. X         && c != '\n'
  316. X         && c != EOF_CHAR) {
  317. X        if (type[c] == LET)                 /* Maybe formal parm    */
  318. X        checkparm(c, dp, 0);
  319. X        else {
  320. X        save(c);
  321. X        if (c == '\\')
  322. X            save(get());
  323. X        }
  324. X    }
  325. X    instring = FALSE;
  326. X    if (c != delim)
  327. X        cerror("Unterminated string in macro body", NULLST);
  328. X    save(c);
  329. X    DBUG_VOID_RETURN;
  330. X}
  331. X#else
  332. Xstparmscan(delim)
  333. Xint        delim;
  334. X/*
  335. X * Normal string parameter scan.
  336. X */
  337. X{
  338. X    register char        *wp;
  339. X    register int        i;
  340. X    extern int        save();
  341. X
  342. X    DBUG_ENTER ("stparmscan");
  343. X    wp = workp;            /* Here's where it starts       */
  344. X    if (!scanstring(delim, save))
  345. X        DBUG_VOID_RETURN;        /* Exit on scanstring error    */
  346. X    workp[-1] = EOS;        /* Erase trailing quote     */
  347. X    wp++;                /* -> first string content byte */
  348. X    for (i = 0; i < nargs; i++) {
  349. X        if (streq(parlist[i], wp)) {
  350. X        *wp++ = MAC_PARM + PAR_MAC;    /* Stuff a magic marker */
  351. X        *wp++ = (i + MAC_PARM);         /* Make a formal marker */
  352. X        *wp = wp[-3];            /* Add on closing quote */
  353. X        workp = wp + 1;         /* Reset string end    */
  354. X        DBUG_VOID_RETURN;
  355. X        }
  356. X    }
  357. X    workp[-1] = wp[-1];        /* Nope, reset end quote.    */
  358. X    DBUG_VOID_RETURN;
  359. X}
  360. X#endif
  361. X
  362. Xdoundef()
  363. X/*
  364. X * Remove the symbol from the defined list.
  365. X * Called from the #control processor.
  366. X */
  367. X{
  368. X  register int c;
  369. X
  370. X  DBUG_ENTER ("doundef");
  371. X  if (type[(c = skipws())] != LET)
  372. X    cerror("Illegal #undef argument", NULLST);
  373. X  else
  374. X    {
  375. X      scanid(c);                                /* Get name to tokenbuf */
  376. X      (void) defendel(tokenbuf, TRUE);
  377. X    }
  378. X  DBUG_VOID_RETURN;
  379. X}
  380. X
  381. Xtextput(text)
  382. Xchar        *text;
  383. X/*
  384. X * Put the string in the parm[] buffer.
  385. X */
  386. X{
  387. X    register int    size;
  388. X
  389. X    DBUG_ENTER ("textput");
  390. X    size = strlen(text) + 1;
  391. X    if ((parmp + size) >= &parm[NPARMWORK])
  392. X        cfatal("Macro work area overflow", NULLST);
  393. X    else {
  394. X        strcpy(parmp, text);
  395. X        parmp += size;
  396. X    }
  397. X    DBUG_VOID_RETURN;
  398. X}
  399. X
  400. Xcharput(c)
  401. Xregister int    c;
  402. X/*
  403. X * Put the byte in the parm[] buffer.
  404. X */
  405. X{
  406. X    if (parmp >= &parm[NPARMWORK])
  407. X        cfatal("Macro work area overflow", NULLST);
  408. X    else {
  409. X        *parmp++ = c;
  410. X    }
  411. X}
  412. X
  413. X/*
  414. X *        M a c r o   E x p a n s i o n
  415. X */
  416. X
  417. Xstatic DEFBUF    *macro;     /* Catches start of infinite macro    */
  418. X
  419. Xexpand(tokenp)
  420. Xregister DEFBUF *tokenp;
  421. X/*
  422. X * Expand a macro.  Called from the cpp mainline routine (via subroutine
  423. X * macroid()) when a token is found in the symbol table.  It calls
  424. X * expcollect() to parse actual parameters, checking for the correct number.
  425. X * It then creates a "file" containing a single line containing the
  426. X * macro with actual parameters inserted appropriately.  This is
  427. X * "pushed back" onto the input stream.  (When the get() routine runs
  428. X * off the end of the macro line, it will dismiss the macro itself.)
  429. X */
  430. X{
  431. X    register int        c;
  432. X    register FILEINFO    *file;
  433. X    extern FILEINFO     *getfile();
  434. X
  435. X    DBUG_ENTER ("expand");
  436. X#if DEBUG
  437. X    if (debug)
  438. X        dumpadef("expand entry", tokenp);
  439. X#endif
  440. X    /*
  441. X     * If no macro is pending, save the name of this macro
  442. X     * for an eventual error message.
  443. X     */
  444. X    if (recursion++ == 0)
  445. X        macro = tokenp;
  446. X    else if (recursion == RECURSION_LIMIT) {
  447. X        cerror("Recursive macro definition of \"%s\"", tokenp->name);
  448. X        fprintf(stderr, "(Defined by \"%s\")\n", macro->name);
  449. X        if (rec_recover) {
  450. X        do {
  451. X            c = get();
  452. X        } while (infile != NULL && infile->fp == NULL);
  453. X        unget();
  454. X        recursion = 0;
  455. X        DBUG_VOID_RETURN;
  456. X        }
  457. X    }
  458. X    /*
  459. X     * Here's a macro to expand.
  460. X     */
  461. X    nargs = 0;                /* Formals counter    */
  462. X    parmp = parm;                /* Setup parm buffer    */
  463. X    switch (tokenp->nargs) {
  464. X    case (-2):                              /* __LINE__             */
  465. X        sprintf(work, "%d", line);
  466. X        ungetstring(work);
  467. X        break;
  468. X
  469. X    case (-3):                              /* __FILE__             */
  470. X        for (file = infile; file != NULL; file = file->parent) {
  471. X        if (file->fp != NULL) {
  472. X            sprintf(work, "\"%s\"", (file->progname != NULL)
  473. X            ? file->progname : file->filename);
  474. X            ungetstring(work);
  475. X            break;
  476. X        }
  477. X        }
  478. X        break;
  479. X
  480. X    default:
  481. X        /*
  482. X         * Nothing funny about this macro.
  483. X         */
  484. X        if (tokenp->nargs < 0)
  485. X        cfatal("Bug: Illegal __ macro \"%s\"", tokenp->name);
  486. X        while ((c = skipws()) == '\n')      /* Look for (, skipping */
  487. X        wrongline = TRUE;        /* spaces and newlines    */
  488. X        if (c != '(') {
  489. X        /*
  490. X         * If the programmer writes
  491. X         *    #define foo() ...
  492. X         *    ...
  493. X         *    foo [no ()]
  494. X         * just write foo to the output stream.
  495. X         */
  496. X        unget();
  497. X        cwarn("Macro \"%s\" needs arguments", tokenp->name);
  498. X        fputs(tokenp->name, stdout);
  499. X        DBUG_VOID_RETURN;
  500. X        }
  501. X        else if (expcollect()) {            /* Collect arguments    */
  502. X        if (tokenp->nargs != nargs) {   /* Should be an error?  */
  503. X            cwarn("Wrong number of macro arguments for \"%s\"",
  504. X            tokenp->name);
  505. X        }
  506. X#if DEBUG
  507. X        if (debug)
  508. X            dumpparm("expand");
  509. X#endif
  510. X        }                /* Collect arguments        */
  511. X    case DEF_NOARGS:        /* No parameters just stuffs    */
  512. X        expstuff(tokenp);           /* Do actual parameters         */
  513. X    }                /* nargs switch         */
  514. X    DBUG_VOID_RETURN;
  515. X}
  516. X
  517. XFILE_LOCAL int
  518. Xexpcollect()
  519. X/*
  520. X * Collect the actual parameters for this macro.  TRUE if ok.
  521. X */
  522. X{
  523. X    register int    c;
  524. X    register int    paren;            /* For embedded ()'s    */
  525. X    extern int    charput();
  526. X
  527. X    DBUG_ENTER ("expcollect");
  528. X    for (;;) {
  529. X        paren = 0;                /* Collect next arg.    */
  530. X        while ((c = skipws()) == '\n')      /* Skip over whitespace */
  531. X        wrongline = TRUE;        /* and newlines.    */
  532. X        if (c == ')') {                     /* At end of all args?  */
  533. X        /*
  534. X         * Note that there is a guard byte in parm[]
  535. X         * so we don't have to check for overflow here.
  536. X         */
  537. X        *parmp = EOS;            /* Make sure terminated */
  538. X        break;                /* Exit collection loop */
  539. X        }
  540. X        else if (nargs >= LASTPARM)
  541. X        cfatal("Too many arguments in macro expansion", NULLST);
  542. X        parlist[nargs++] = parmp;        /* At start of new arg    */
  543. X        for (;; c = cget()) {               /* Collect arg's bytes  */
  544. X        if (c == EOF_CHAR) {
  545. X            cerror("end of file within macro argument", NULLST);
  546. X            DBUG_RETURN (FALSE);                /* Sorry.               */
  547. X        }
  548. X        else if (c == '\\') {           /* Quote next character */
  549. X            charput(c);                 /* Save the \ for later */
  550. X            charput(cget());            /* Save the next char.  */
  551. X            continue;            /* And go get another    */
  552. X        }
  553. X        else if (type[c] == QUO) {      /* Start of string?     */
  554. X            scanstring(c, charput);     /* Scan it off          */
  555. X            continue;            /* Go get next char    */
  556. X        }
  557. X        else if (c == '(')              /* Worry about balance  */
  558. X            paren++;            /* To know about commas */
  559. X        else if (c == ')') {            /* Other side too       */
  560. X            if (paren == 0) {           /* At the end?          */
  561. X            unget();                /* Look at it later     */
  562. X            break;            /* Exit arg getter.    */
  563. X            }
  564. X            paren--;            /* More to come.    */
  565. X        }
  566. X        else if (c == ',' && paren == 0) /* Comma delimits args */
  567. X            break;
  568. X        else if (c == '\n')             /* Newline inside arg?  */
  569. X            wrongline = TRUE;        /* We'll need a #line   */
  570. X        charput(c);                     /* Store this one       */
  571. X        }                    /* Collect an argument    */
  572. X        charput(EOS);                       /* Terminate argument   */
  573. X#if DEBUG
  574. X        if (debug)
  575. X        printf("parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]);
  576. X#endif
  577. X    }                    /* Collect all args.    */
  578. X    DBUG_RETURN (TRUE);                     /* Normal return        */
  579. X}
  580. X
  581. X
  582. X#if OK_CONCAT
  583. X
  584. XFILE_LOCAL
  585. Xchar *doquoting(to, from)
  586. Xregister char *to;
  587. Xregister char *from;
  588. X{
  589. X    *to++ = '"';
  590. X    while (*from) {
  591. X    if (*from == '\\' || *from == '"')
  592. X        *to++ = '\\';
  593. X    *to++ = *from++;
  594. X    }
  595. X    *to++ = '"';
  596. X
  597. X    return to;
  598. X}
  599. X
  600. X#endif
  601. X
  602. XFILE_LOCAL
  603. Xexpstuff(tokenp)
  604. XDEFBUF        *tokenp;        /* Current macro being expanded */
  605. X/*
  606. X * Stuff the macro body, replacing formal parameters by actual parameters.
  607. X */
  608. X{
  609. X    register int    c;            /* Current character    */
  610. X    register char    *inp;            /* -> repl string    */
  611. X    register char    *defp;            /* -> macro output buff */
  612. X    int        size;            /* Actual parm. size    */
  613. X    char        *defend;        /* -> output buff end    */
  614. X    int        string_magic;        /* String formal hack    */
  615. X    FILEINFO    *file;            /* Funny #include    */
  616. X#if OK_CONCAT
  617. X    register char         quoting;    /* Quote macro argument */
  618. X#endif
  619. X    extern FILEINFO *getfile();
  620. X
  621. X    DBUG_ENTER ("expstuff");
  622. X    file = getfile(NBUFF, tokenp->name);
  623. X    inp = tokenp->repl;            /* -> macro replacement */
  624. X    defp = file->buffer;            /* -> output buffer    */
  625. X    defend = defp + (NBUFF - 1);            /* Note its end         */
  626. X    if (inp != NULL) {
  627. X        quoting = 0;
  628. X        while ((c = (*inp++ & 0xFF)) != EOS) {
  629. X#if OK_CONCAT
  630. X        if (c == QUOTE_PARM) {          /* Special token for #  */
  631. X            quoting = 1;        /* set flag, for later    */
  632. X            continue;            /* Get next character    */
  633. X        }
  634. X#endif
  635. X        if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) {
  636. X            string_magic = (c == (MAC_PARM + PAR_MAC));
  637. X            if (string_magic)
  638. X            c = (*inp++ & 0xFF);
  639. X            /*
  640. X             * Replace formal parameter by actual parameter string.
  641. X             */
  642. X            if ((c -= MAC_PARM) < nargs) {
  643. X            size = strlen(parlist[c]);
  644. X#if OK_CONCAT
  645. X            if (quoting) {
  646. X                size++;
  647. X                size *= 2;        /* worst case condition */
  648. X            }
  649. X#endif
  650. X            if ((defp + size) >= defend)
  651. X                goto nospace;
  652. X            /*
  653. X             * Erase the extra set of quotes.
  654. X             */
  655. X            if (string_magic && defp[-1] == parlist[c][0]) {
  656. X                strcpy(defp-1, parlist[c]);
  657. X                defp += (size - 2);
  658. X            }
  659. X#if OK_CONCAT
  660. X            else if (quoting)
  661. X                defp = doquoting(defp, parlist[c]);
  662. X#endif
  663. X            else {
  664. X                strcpy(defp, parlist[c]);
  665. X                defp += size;
  666. X            }
  667. X            }
  668. X        }
  669. X        else if (defp >= defend) {
  670. Xnospace:        cfatal("Out of space in macro \"%s\" arg expansion",
  671. X            tokenp->name);
  672. X        }
  673. X        else {
  674. X            *defp++ = c;
  675. X        }
  676. X        quoting = 0;
  677. X        }
  678. X    }
  679. X    *defp = EOS;
  680. X#if DEBUG
  681. X    if (debug > 1)
  682. X        printf("macroline: \"%s\"\n", file->buffer);
  683. X#endif
  684. X    DBUG_VOID_RETURN;
  685. X}
  686. X
  687. X#if DEBUG
  688. Xdumpparm(why)
  689. Xchar        *why;
  690. X/*
  691. X * Dump parameter list.
  692. X */
  693. X{
  694. X    register int    i;
  695. X
  696. X    DBUG_ENTER ("dumpparm");
  697. X    printf("dump of %d parameters (%d bytes total) %s\n",
  698. X        nargs, parmp - parm, why);
  699. X    for (i = 0; i < nargs; i++) {
  700. X        printf("parm[%d] (%d) = \"%s\"\n",
  701. X        i + 1, strlen(parlist[i]), parlist[i]);
  702. X    }
  703. X    DBUG_VOID_RETURN;
  704. X}
  705. X#endif
  706. END_OF_FILE
  707. if test 19642 -ne `wc -c <'Cpp4.c'`; then
  708.     echo shar: \"'Cpp4.c'\" unpacked with wrong size!
  709. fi
  710. # end of 'Cpp4.c'
  711. fi
  712. if test -f 'cpp5.c' -a "${1}" != "-c" ; then 
  713.   echo shar: Will not clobber existing file \"'cpp5.c'\"
  714. else
  715. echo shar: Extracting \"'cpp5.c'\" \(23086 characters\)
  716. sed "s/^X//" >'cpp5.c' <<'END_OF_FILE'
  717. X/*
  718. X *                C P P 5 . C
  719. X *        E x p r e s s i o n   E v a l u a t i o n
  720. X *
  721. X * Edit History
  722. X * 31-Aug-84    MM    USENET net.sources release
  723. X * 04-Oct-84    MM    __LINE__ and __FILE__ must call ungetstring()
  724. X *            so they work correctly with token concatenation.
  725. X *            Added string formal recognition.
  726. X * 25-Oct-84    MM    "Short-circuit" evaluate #if's so that we
  727. X *            don't print unnecessary error messages for
  728. X *            #if !defined(FOO) && FOO != 0 && 10 / FOO ...
  729. X * 31-Oct-84    ado/MM    Added token concatenation
  730. X *  6-Nov-84    MM    Split from #define stuff, added sizeof stuff
  731. X * 19-Nov-84    ado    #if error returns TRUE for (sigh) compatibility
  732. X * 21-Oct-85    RMS    Rename `token' to `tokenbuf'
  733. X * 23-Oct-85    RMS    Treat undefined symbols as having value zero.
  734. X * 14-Mar-86    FNF    Incorporate macro based C debugging package.
  735. X *            Port to Commodore Amiga.
  736. X * 20-Aug-88    Ois    Conditionally compile sizeof stuff.
  737. X */
  738. X
  739. X#include    <stdio.h>
  740. X#include    <ctype.h>
  741. X#include    "cppdef.h"
  742. X#include    "cpp.h"
  743. X
  744. X/*
  745. X * Evaluate an #if expression.
  746. X */
  747. X
  748. Xstatic char    *opname[] = {        /* For debug and error messages */
  749. X"end of expression", "val", "id",
  750. X  "+",   "-",  "*",  "/",  "%",
  751. X  "<<", ">>",  "&",  "|",  "^",
  752. X  "==", "!=",  "<", "<=", ">=",  ">",
  753. X  "&&", "||",  "?",  ":",  ",",
  754. X  "unary +", "unary -", "~", "!",  "(",  ")", "(none)",
  755. X};
  756. X
  757. X/*
  758. X * opdope[] has the operator precedence:
  759. X *     Bits
  760. X *      7    Unused (so the value is always positive)
  761. X *    6-2    Precedence (000x .. 017x)
  762. X *    1-0    Binary op. flags:
  763. X *        01    The binop flag should be set/cleared when this op is seen.
  764. X *        10    The new value of the binop flag.
  765. X * Note:  Expected, New binop
  766. X * constant    0    1    Binop, end, or ) should follow constants
  767. X * End of line    1    0    End may not be preceeded by an operator
  768. X * binary    1    0    Binary op follows a value, value follows.
  769. X * unary    0    0    Unary op doesn't follow a value, value follows
  770. X *   (          0       0       Doesn't follow value, value or unop follows
  771. X *   )        1    1    Follows value.    Op follows.
  772. X */
  773. X
  774. Xstatic char    opdope[OP_MAX] = {
  775. X  0001,                 /* End of expression        */
  776. X  0002,                 /* Digit            */
  777. X  0000,                 /* Letter (identifier)          */
  778. X  0141, 0141, 0151, 0151, 0151,     /* ADD, SUB, MUL, DIV, MOD    */
  779. X  0131, 0131, 0101, 0071, 0071,     /* ASL, ASR, AND,  OR, XOR    */
  780. X  0111, 0111, 0121, 0121, 0121, 0121,    /*  EQ,  NE,  LT,  LE,    GE,  GT */
  781. X  0061, 0051, 0041, 0041, 0031,     /* ANA, ORO, QUE, COL, CMA    */
  782. X/*
  783. X * Unary op's follow
  784. X */
  785. X  0160, 0160, 0160, 0160,        /* NEG, PLU, COM, NOT        */
  786. X  0170, 0013, 0023,            /* LPA, RPA, END        */
  787. X};
  788. X/*
  789. X * OP_QUE and OP_RPA have alternate precedences:
  790. X */
  791. X#define OP_RPA_PREC    0013
  792. X#define OP_QUE_PREC    0034
  793. X
  794. X/*
  795. X * S_ANDOR and S_QUEST signal "short-circuit" boolean evaluation, so that
  796. X *    #if FOO != 0 && 10 / FOO ...
  797. X * doesn't generate an error message.  They are stored in optab.skip.
  798. X */
  799. X#define S_ANDOR     2
  800. X#define S_QUEST     1
  801. X
  802. Xtypedef struct optab {
  803. X    char    op;            /* Operator            */
  804. X    char    prec;            /* Its precedence        */
  805. X    char    skip;            /* Short-circuit: TRUE to skip    */
  806. X} OPTAB;
  807. Xstatic int    evalue;         /* Current value from evallex() */
  808. X
  809. X#ifdef    nomacargs
  810. XFILE_LOCAL int
  811. Xisbinary(op)
  812. Xregister int    op;
  813. X{
  814. X    return (op >= FIRST_BINOP && op <= LAST_BINOP);
  815. X}
  816. X
  817. XFILE_LOCAL int
  818. Xisunary(op)
  819. Xregister int    op;
  820. X{
  821. X    return (op >= FIRST_UNOP && op <= LAST_UNOP);
  822. X}
  823. X#else
  824. X#define isbinary(op)    (op >= FIRST_BINOP && op <= LAST_BINOP)
  825. X#define isunary(op)     (op >= FIRST_UNOP  && op <= LAST_UNOP)
  826. X#endif
  827. X
  828. X/*
  829. X * The following definitions are used to specify basic variable sizes.
  830. X */
  831. X
  832. X#if OK_SIZEOF
  833. X
  834. X#ifndef S_CHAR
  835. X#define S_CHAR        (sizeof (char))
  836. X#endif
  837. X#ifndef S_SINT
  838. X#ifdef manx        /* Aztec/Manx C does not like "short int" */
  839. X#define S_SINT        (sizeof (short))
  840. X#else
  841. X#define S_SINT        (sizeof (short int))
  842. X#endif
  843. X#endif
  844. X#ifndef S_INT
  845. X#define S_INT        (sizeof (int))
  846. X#endif
  847. X#ifndef S_LINT
  848. X#define S_LINT        (sizeof (long int))
  849. X#endif
  850. X#ifndef S_FLOAT
  851. X#define S_FLOAT     (sizeof (float))
  852. X#endif
  853. X#ifndef S_DOUBLE
  854. X#define S_DOUBLE    (sizeof (double))
  855. X#endif
  856. X#ifndef S_PCHAR
  857. X#define S_PCHAR     (sizeof (char *))
  858. X#endif
  859. X#ifndef S_PSINT
  860. X#ifdef manx        /* Aztec/Manx C does not like "short int" */
  861. X#define S_PSINT     (sizeof (short *))
  862. X#else
  863. X#define S_PSINT     (sizeof (short int *))
  864. X#endif
  865. X#endif
  866. X#ifndef S_PINT
  867. X#define S_PINT        (sizeof (int *))
  868. X#endif
  869. X#ifndef S_PLINT
  870. X#define S_PLINT     (sizeof (long int *))
  871. X#endif
  872. X#ifndef S_PFLOAT
  873. X#define S_PFLOAT    (sizeof (float *))
  874. X#endif
  875. X#ifndef S_PDOUBLE
  876. X#define S_PDOUBLE    (sizeof (double *))
  877. X#endif
  878. X#ifndef S_PFPTR
  879. X#define S_PFPTR     (sizeof (int (*)()))
  880. X#endif
  881. X
  882. X
  883. Xtypedef struct types {
  884. X    short    type;            /* This is the bit if        */
  885. X    char    *name;            /* this is the token word    */
  886. X} TYPES;
  887. X
  888. Xstatic TYPES basic_types[] = {
  889. X    { T_CHAR,    "char",         },
  890. X    { T_INT,    "int",          },
  891. X    { T_FLOAT,    "float",        },
  892. X    { T_DOUBLE,    "double",       },
  893. X    { T_SHORT,    "short",        },
  894. X    { T_LONG,    "long",         },
  895. X    { T_SIGNED,    "signed",       },
  896. X    { T_UNSIGNED,    "unsigned",     },
  897. X    { 0,        NULL,        },    /* Signal end        */
  898. X};
  899. X
  900. X/*
  901. X * Test_table[] is used to test for illegal combinations.
  902. X */
  903. Xstatic short test_table[] = {
  904. X    T_FLOAT | T_DOUBLE | T_LONG | T_SHORT,
  905. X    T_FLOAT | T_DOUBLE | T_CHAR | T_INT,
  906. X    T_FLOAT | T_DOUBLE | T_SIGNED | T_UNSIGNED,
  907. X    T_LONG    | T_SHORT  | T_CHAR,
  908. X    0                        /* end marker    */
  909. X};
  910. X
  911. X/*
  912. X * The order of this table is important -- it is also referenced by
  913. X * the command line processor to allow run-time overriding of the
  914. X * built-in size values.  The order must not be changed:
  915. X *    char, short, int, long, float, double (func pointer)
  916. X */
  917. XSIZES size_table[] = {
  918. X    { T_CHAR,    S_CHAR,     S_PCHAR     },    /* char     */
  919. X    { T_SHORT,    S_SINT,     S_PSINT     },    /* short int    */
  920. X    { T_INT,    S_INT,        S_PINT        },    /* int        */
  921. X    { T_LONG,    S_LINT,     S_PLINT     },    /* long     */
  922. X    { T_FLOAT,    S_FLOAT,    S_PFLOAT    },    /* float    */
  923. X    { T_DOUBLE, S_DOUBLE,    S_PDOUBLE    },    /* double    */
  924. X    { T_FPTR,    0,        S_PFPTR     },    /* int (*())    */
  925. X    { 0,    0,        0        },    /* End of table */
  926. X};
  927. X
  928. X#endif /* OK_SIZEOF */
  929. X
  930. Xint
  931. Xeval()
  932. X/*
  933. X * Evaluate an expression.  Straight-forward operator precedence.
  934. X * This is called from control() on encountering an #if statement.
  935. X * It calls the following routines:
  936. X * evallex    Lexical analyser -- returns the type and value of
  937. X *        the next input token.
  938. X * evaleval    Evaluate the current operator, given the values on
  939. X *        the value stack.  Returns a pointer to the (new)
  940. X *        value stack.
  941. X * For compatiblity with older cpp's, this return returns 1 (TRUE)
  942. X * if a syntax error is detected.
  943. X */
  944. X{
  945. X    register int    op;        /* Current operator        */
  946. X    register int    *valp;        /* -> value vector        */
  947. X    register OPTAB    *opp;        /* Operator stack        */
  948. X    int        prec;        /* Op precedence        */
  949. X    int        binop;        /* Set if binary op. needed    */
  950. X    int        op1;        /* Operand from stack        */
  951. X    int        skip;        /* For short-circuit testing    */
  952. X    int        value[NEXP];    /* Value stack            */
  953. X    OPTAB        opstack[NEXP];    /* Operand stack        */
  954. X    extern int    *evaleval();    /* Does actual evaluation       */
  955. X
  956. X    DBUG_ENTER ("eval");
  957. X    valp = value;
  958. X    opp = opstack;
  959. X    opp->op = OP_END;        /* Mark bottom of stack     */
  960. X    opp->prec = opdope[OP_END];    /* And its precedence        */
  961. X    opp->skip = 0;            /* Not skipping now        */
  962. X    binop = 0;
  963. Xagain:    ;
  964. X#ifdef    DEBUG_EVAL
  965. X    printf("In #if at again: skip = %d, binop = %d, line is: %s",
  966. X        opp->skip, binop, infile->bptr);
  967. X#endif
  968. X    if ((op = evallex(opp->skip)) == OP_SUB && binop == 0)
  969. X        op = OP_NEG;            /* Unary minus        */
  970. X    else if (op == OP_ADD && binop == 0)
  971. X        op = OP_PLU;            /* Unary plus        */
  972. X    else if (op == OP_FAIL)
  973. X        DBUG_RETURN (1);                    /* Error in evallex     */
  974. X#ifdef    DEBUG_EVAL
  975. X    printf("op = %s, opdope = %03o, binop = %d, skip = %d\n",
  976. X        opname[op], opdope[op], binop, opp->skip);
  977. X#endif
  978. X    if (op == DIG) {                        /* Value?               */
  979. X        if (binop != 0) {
  980. X        cerror("misplaced constant in #if", NULLST);
  981. X        DBUG_RETURN (1);
  982. X        }
  983. X        else if (valp >= &value[NEXP-1]) {
  984. X        cerror("#if value stack overflow", NULLST);
  985. X        DBUG_RETURN (1);
  986. X        }
  987. X        else {
  988. X#ifdef    DEBUG_EVAL
  989. X        printf("pushing %d onto value stack[%d]\n",
  990. X            evalue, valp - value);
  991. X#endif
  992. X        *valp++ = evalue;
  993. X        binop = 1;
  994. X        }
  995. X        goto again;
  996. X    }
  997. X    else if (op > OP_END) {
  998. X        cerror("Illegal #if line", NULLST);
  999. X        DBUG_RETURN (1);
  1000. X    }
  1001. X    prec = opdope[op];
  1002. X    if (binop != (prec & 1)) {
  1003. X        cerror("Operator %s in incorrect context", opname[op]);
  1004. X        DBUG_RETURN (1);
  1005. X    }
  1006. X    binop = (prec & 2) >> 1;
  1007. X    for (;;) {
  1008. X#ifdef    DEBUG_EVAL
  1009. X        printf("op %s, prec %d., stacked op %s, prec %d, skip %d\n",
  1010. X        opname[op], prec, opname[opp->op], opp->prec, opp->skip);
  1011. X#endif
  1012. X        if (prec > opp->prec) {
  1013. X        if (op == OP_LPA)
  1014. X            prec = OP_RPA_PREC;
  1015. X        else if (op == OP_QUE)
  1016. X            prec = OP_QUE_PREC;
  1017. X        op1 = opp->skip;        /* Save skip for test    */
  1018. X        /*
  1019. X         * Push operator onto op. stack.
  1020. X         */
  1021. X        opp++;
  1022. X        if (opp >= &opstack[NEXP]) {
  1023. X            cerror("expression stack overflow at op \"%s\"",
  1024. X            opname[op]);
  1025. X            DBUG_RETURN (1);
  1026. X        }
  1027. X        opp->op = op;
  1028. X        opp->prec = prec;
  1029. X        skip = (valp[-1] != 0);         /* Short-circuit tester */
  1030. X        /*
  1031. X         * Do the short-circuit stuff here.  Short-circuiting
  1032. X         * stops automagically when operators are evaluated.
  1033. X         */
  1034. X        if ((op == OP_ANA && !skip)
  1035. X         || (op == OP_ORO && skip))
  1036. X            opp->skip = S_ANDOR;    /* And/or skip starts    */
  1037. X        else if (op == OP_QUE)          /* Start of ?: operator */
  1038. X            opp->skip = (op1 & S_ANDOR) | ((!skip) ? S_QUEST : 0);
  1039. X        else if (op == OP_COL) {        /* : inverts S_QUEST    */
  1040. X            opp->skip = (op1 & S_ANDOR)
  1041. X                  | (((op1 & S_QUEST) != 0) ? 0 : S_QUEST);
  1042. X        }
  1043. X        else {                /* Other ops leave    */
  1044. X            opp->skip = op1;        /*  skipping unchanged. */
  1045. X        }
  1046. X#ifdef    DEBUG_EVAL
  1047. X        printf("stacking %s, valp[-1] == %d at %s",
  1048. X            opname[op], valp[-1], infile->bptr);
  1049. X        dumpstack(opstack, opp, value, valp);
  1050. X#endif
  1051. X        goto again;
  1052. X        }
  1053. X        /*
  1054. X         * Pop operator from op. stack and evaluate it.
  1055. X         * End of stack and '(' are specials.
  1056. X         */
  1057. X        skip = opp->skip;            /* Remember skip value    */
  1058. X        switch ((op1 = opp->op)) {          /* Look at stacked op   */
  1059. X        case OP_END:            /* Stack end marker    */
  1060. X        if (op == OP_EOE)
  1061. X            DBUG_RETURN (valp[-1]);     /* Finished ok.         */
  1062. X        goto again;            /* Read another op.    */
  1063. X
  1064. X        case OP_LPA:            /* ( on stack           */
  1065. X        if (op != OP_RPA) {             /* Matches ) on input   */
  1066. X            cerror("unbalanced paren's, op is \"%s\"", opname[op]);
  1067. X            DBUG_RETURN (1);
  1068. X        }
  1069. X        opp--;                /* Unstack it        */
  1070. X        /* goto again;            -- Fall through     */
  1071. X
  1072. X        case OP_QUE:
  1073. X        goto again;            /* Evaluate true expr.    */
  1074. X
  1075. X        case OP_COL:            /* : on stack.        */
  1076. X        opp--;                /* Unstack :        */
  1077. X        if (opp->op != OP_QUE) {        /* Matches ? on stack?  */
  1078. X            cerror("Misplaced '?' or ':', previous operator is %s",
  1079. X            opname[opp->op]);
  1080. X            DBUG_RETURN (1);
  1081. X        }
  1082. X        /*
  1083. X         * Evaluate op1.
  1084. X         */
  1085. X        default:                /* Others:        */
  1086. X        opp--;                /* Unstack the operator */
  1087. X#ifdef    DEBUG_EVAL
  1088. X        printf("Stack before evaluation of %s\n", opname[op1]);
  1089. X        dumpstack(opstack, opp, value, valp);
  1090. X#endif
  1091. X        valp = evaleval(valp, op1, skip);
  1092. X#ifdef    DEBUG_EVAL
  1093. X        printf("Stack after evaluation\n");
  1094. X        dumpstack(opstack, opp, value, valp);
  1095. X#endif
  1096. X        }                    /* op1 switch end    */
  1097. X    }                    /* Stack unwind loop    */
  1098. X}
  1099. X
  1100. XFILE_LOCAL int
  1101. Xevallex(skip)
  1102. Xint        skip;        /* TRUE if short-circuit evaluation    */
  1103. X/*
  1104. X * Return next eval operator or value.    Called from eval().  It
  1105. X * calls a special-purpose routines for 'char' strings and
  1106. X * numeric values:
  1107. X * evalchar    called to evaluate 'x'
  1108. X * evalnum    called to evaluate numbers.
  1109. X */
  1110. X{
  1111. X    register int    c, c1, t;
  1112. X
  1113. X    DBUG_ENTER ("evallex");
  1114. Xagain:    do {                    /* Collect the token    */
  1115. X        c = skipws();
  1116. X        if ((c = macroid(c)) == EOF_CHAR || c == '\n') {
  1117. X        unget();
  1118. X        DBUG_RETURN (OP_EOE);           /* End of expression    */
  1119. X        }
  1120. X    } while ((t = type[c]) == LET && catenate());
  1121. X    if (t == INV) {                         /* Total nonsense       */
  1122. X        if (!skip) {
  1123. X        if (isascii(c) && isprint(c))
  1124. X            cierror("illegal character '%c' in #if", c);
  1125. X        else
  1126. X            cierror("illegal character (%d decimal) in #if", c);
  1127. X        }
  1128. X        DBUG_RETURN (OP_FAIL);
  1129. X    }
  1130. X    else if (t == QUO) {                    /* ' or "               */
  1131. X        if (c == '\'') {                    /* Character constant   */
  1132. X        evalue = evalchar(skip);        /* Somewhat messy       */
  1133. X#ifdef    DEBUG_EVAL
  1134. X        printf("evalchar returns %d.\n", evalue);
  1135. X#endif
  1136. X        DBUG_RETURN (DIG);              /* Return a value       */
  1137. X        }
  1138. X        cerror("Can't use a string in an #if", NULLST);
  1139. X        DBUG_RETURN (OP_FAIL);
  1140. X    }
  1141. X    else if (t == LET) {                    /* ID must be a macro   */
  1142. X        if (streq(tokenbuf, "defined")) {   /* Or defined name      */
  1143. X        c1 = c = skipws();
  1144. X        if (c == '(')                   /* Allow defined(name)  */
  1145. X            c = skipws();
  1146. X        if (type[c] == LET) {
  1147. X            evalue = (lookid(c) != NULL);
  1148. X            if (c1 != '('               /* Need to balance      */
  1149. X             || skipws() == ')')        /* Did we balance?      */
  1150. X            DBUG_RETURN (DIG);      /* Parsed ok            */
  1151. X        }
  1152. X        cerror("Bad #if ... defined() syntax", NULLST);
  1153. X        DBUG_RETURN (OP_FAIL);
  1154. X        }
  1155. X#if OK_SIZEOF
  1156. X        else if (streq(tokenbuf, "sizeof")) /* New sizeof hackery   */
  1157. X        DBUG_RETURN (dosizeof());       /* Gets own routine     */
  1158. X#endif
  1159. X        evalue = 0;
  1160. X        DBUG_RETURN (DIG);
  1161. X    }
  1162. X    else if (t == DIG) {                    /* Numbers are harder   */
  1163. X        evalue = evalnum(c);
  1164. X#ifdef    DEBUG_EVAL
  1165. X        printf("evalnum returns %d.\n", evalue);
  1166. X#endif
  1167. X    }
  1168. X    else if (strchr("!=<>&|\\", c) != NULL) {
  1169. X        /*
  1170. X         * Process a possible multi-byte lexeme.
  1171. X         */
  1172. X        c1 = cget();                        /* Peek at next char    */
  1173. X        switch (c) {
  1174. X        case '!':
  1175. X        if (c1 == '=')
  1176. X            DBUG_RETURN (OP_NE);
  1177. X        break;
  1178. X
  1179. X        case '=':
  1180. X        if (c1 != '=') {                /* Can't say a=b in #if */
  1181. X            unget();
  1182. X            cerror("= not allowed in #if", NULLST);
  1183. X            DBUG_RETURN (OP_FAIL);
  1184. X        }
  1185. X        DBUG_RETURN (OP_EQ);
  1186. X
  1187. X        case '>':
  1188. X        case '<':
  1189. X        if (c1 == c)
  1190. X            DBUG_RETURN ((c == '<') ? OP_ASL : OP_ASR);
  1191. X        else if (c1 == '=')
  1192. X            DBUG_RETURN ((c == '<') ? OP_LE  : OP_GE);
  1193. X        break;
  1194. X
  1195. X        case '|':
  1196. X        case '&':
  1197. X        if (c1 == c)
  1198. X            DBUG_RETURN ((c == '|') ? OP_ORO : OP_ANA);
  1199. X        break;
  1200. X
  1201. X        case '\\':
  1202. X        if (c1 == '\n')                 /* Multi-line if        */
  1203. X            goto again;
  1204. X        cerror("Unexpected \\ in #if", NULLST);
  1205. X        DBUG_RETURN (OP_FAIL);
  1206. X        }
  1207. X        unget();
  1208. X    }
  1209. X    DBUG_RETURN (t);
  1210. X}
  1211. X
  1212. X#if OK_SIZEOF
  1213. X
  1214. XFILE_LOCAL int
  1215. Xdosizeof()
  1216. X/*
  1217. X * Process the sizeof (basic type) operation in an #if string.
  1218. X * Sets evalue to the size and returns
  1219. X *    DIG        success
  1220. X *    OP_FAIL     bad parse or something.
  1221. X */
  1222. X{
  1223. X    register int    c;
  1224. X    register TYPES    *tp;
  1225. X    register SIZES    *sizp;
  1226. X    register short    *testp;
  1227. X    short        typecode;
  1228. X
  1229. X    DBUG_ENTER ("dosizeof");
  1230. X    if ((c = skipws()) != '(')
  1231. X        goto nogood;
  1232. X    /*
  1233. X     * Scan off the tokens.
  1234. X     */
  1235. X    typecode = 0;
  1236. X    while ((c = skipws())) {
  1237. X        if ((c = macroid(c)) == EOF_CHAR || c == '\n')
  1238. X        goto nogood;            /* End of line is a bug */
  1239. X        else if (c == '(') {                /* thing (*)() func ptr */
  1240. X        if (skipws() == '*'
  1241. X         && skipws() == ')') {          /* We found (*)         */
  1242. X            if (skipws() != '(')        /* Let () be optional   */
  1243. X            unget();
  1244. X            else if (skipws() != ')')
  1245. X            goto nogood;
  1246. X            typecode |= T_FPTR;     /* Function pointer    */
  1247. X        }
  1248. X        else {                /* Junk is a bug    */
  1249. X            goto nogood;
  1250. X        }
  1251. X        }
  1252. X        else if (type[c] != LET)            /* Exit if not a type   */
  1253. X        break;
  1254. X        else if (!catenate()) {             /* Maybe combine tokens */
  1255. X        /*
  1256. X         * Look for this unexpandable token in basic_types.
  1257. X         * The code accepts "int long" as well as "long int"
  1258. X         * which is a minor bug as bugs go (and one shared with
  1259. X         * a lot of C compilers).
  1260. X         */
  1261. X        for (tp = basic_types; tp->name != NULLST; tp++) {
  1262. X            if (streq(tokenbuf, tp->name))
  1263. X            break;
  1264. X        }
  1265. X        if (tp->name == NULLST) {
  1266. X            cerror("#if sizeof, unknown type \"%s\"", tokenbuf);
  1267. X            DBUG_RETURN (OP_FAIL);
  1268. X        }
  1269. X        typecode |= tp->type;        /* Or in the type bit    */
  1270. X        }
  1271. X    }
  1272. X    /*
  1273. X     * We are at the end of the type scan.    Chew off '*' if necessary.
  1274. X     */
  1275. X    if (c == '*') {
  1276. X        typecode |= T_PTR;
  1277. X        c = skipws();
  1278. X    }
  1279. X    if (c == ')') {                         /* Last syntax check    */
  1280. X        for (testp = test_table; *testp != 0; testp++) {
  1281. X        if (!bittest(typecode & *testp)) {
  1282. X            cerror("#if ... sizeof: illegal type combination", NULLST);
  1283. X            DBUG_RETURN (OP_FAIL);
  1284. X        }
  1285. X        }
  1286. X        /*
  1287. X         * We assume that all function pointers are the same size:
  1288. X         *        sizeof (int (*)()) == sizeof (float (*)())
  1289. X         * We assume that signed and unsigned don't change the size:
  1290. X         *        sizeof (signed int) == (sizeof unsigned int)
  1291. X         */
  1292. X        if ((typecode & T_FPTR) != 0)       /* Function pointer     */
  1293. X        typecode = T_FPTR | T_PTR;
  1294. X        else {                /* Var or var * datum    */
  1295. X        typecode &= ~(T_SIGNED | T_UNSIGNED);
  1296. X        if ((typecode & (T_SHORT | T_LONG)) != 0)
  1297. X            typecode &= ~T_INT;
  1298. X        }
  1299. X        if ((typecode & ~T_PTR) == 0) {
  1300. X        cerror("#if sizeof() error, no type specified", NULLST);
  1301. X        DBUG_RETURN (OP_FAIL);
  1302. X        }
  1303. X        /*
  1304. X         * Exactly one bit (and possibly T_PTR) may be set.
  1305. X         */
  1306. X        for (sizp = size_table; sizp->bits != 0; sizp++) {
  1307. X        if ((typecode & ~T_PTR) == sizp->bits) {
  1308. X            evalue = ((typecode & T_PTR) != 0)
  1309. X            ? sizp->psize : sizp->size;
  1310. X            DBUG_RETURN (DIG);
  1311. X        }
  1312. X        }                    /* We shouldn't fail    */
  1313. X        cierror("#if ... sizeof: bug, unknown type code 0x%x", typecode);
  1314. X        DBUG_RETURN (OP_FAIL);
  1315. X    }
  1316. X
  1317. Xnogood: unget();
  1318. X    cerror("#if ... sizeof() syntax error", NULLST);
  1319. X    DBUG_RETURN (OP_FAIL);
  1320. X}
  1321. X
  1322. XFILE_LOCAL int
  1323. Xbittest(value)
  1324. X/*
  1325. X * TRUE if value is zero or exactly one bit is set in value.
  1326. X */
  1327. X{
  1328. X#if (4096 & ~(-4096)) == 0
  1329. X    return ((value & ~(-value)) == 0);
  1330. X#else
  1331. X    /*
  1332. X     * Do it the hard way (for non 2's complement machines)
  1333. X     */
  1334. X    return (value == 0 || value ^ (value - 1) == (value * 2 - 1));
  1335. X#endif
  1336. X}
  1337. X
  1338. X#endif /* OK_SIZEOF */
  1339. X
  1340. XFILE_LOCAL int
  1341. Xevalnum(c)
  1342. Xregister int    c;
  1343. X/*
  1344. X * Expand number for #if lexical analysis.  Note: evalnum recognizes
  1345. X * the unsigned suffix, but only returns a signed int value.
  1346. X */
  1347. X{
  1348. X    register int    value;
  1349. X    register int    base;
  1350. X    register int    c1;
  1351. X
  1352. X    DBUG_ENTER ("evalnum");
  1353. X    if (c != '0')
  1354. X        base = 10;
  1355. X    else if ((c = cget()) == 'x' || c == 'X') {
  1356. X        base = 16;
  1357. X        c = cget();
  1358. X    }
  1359. X    else base = 8;
  1360. X    value = 0;
  1361. X    for (;;) {
  1362. X        c1 = c;
  1363. X        if (isascii(c) && isupper(c1))
  1364. X        c1 = tolower(c1);
  1365. X        if (c1 >= 'a')
  1366. X        c1 -= ('a' - 10);
  1367. X        else c1 -= '0';
  1368. X        if (c1 < 0 || c1 >= base)
  1369. X        break;
  1370. X        value *= base;
  1371. X        value += c1;
  1372. X        c = cget();
  1373. X    }
  1374. X    if (c == 'u' || c == 'U')       /* Unsigned nonsense            */
  1375. X        c = cget();
  1376. X    unget();
  1377. X    DBUG_RETURN (value);
  1378. X}
  1379. X
  1380. XFILE_LOCAL int
  1381. Xevalchar(skip)
  1382. Xint        skip;        /* TRUE if short-circuit evaluation    */
  1383. X/*
  1384. X * Get a character constant
  1385. X */
  1386. X{
  1387. X    register int    c;
  1388. X    register int    value;
  1389. X    register int    count;
  1390. X
  1391. X    DBUG_ENTER ("evalchar");
  1392. X    instring = TRUE;
  1393. X    if ((c = cget()) == '\\') {
  1394. X        switch ((c = cget())) {
  1395. X        case 'a':                           /* New in Standard      */
  1396. X#if ('a' == '\a' || '\a' == ALERT)
  1397. X        value = ALERT;            /* Use predefined value */
  1398. X#else
  1399. X        value = '\a';                   /* Use compiler's value */
  1400. X#endif
  1401. X        break;
  1402. X
  1403. X        case 'b':
  1404. X        value = '\b';
  1405. X        break;
  1406. X
  1407. X        case 'f':
  1408. X        value = '\f';
  1409. X        break;
  1410. X
  1411. X        case 'n':
  1412. X        value = '\n';
  1413. X        break;
  1414. X
  1415. X        case 'r':
  1416. X        value = '\r';
  1417. X        break;
  1418. X
  1419. X        case 't':
  1420. X        value = '\t';
  1421. X        break;
  1422. X
  1423. X        case 'v':                           /* New in Standard      */
  1424. X#if ('v' == '\v' || '\v' == VT)
  1425. X        value = VT;            /* Use predefined value */
  1426. X#else
  1427. X        value = '\v';                   /* Use compiler's value */
  1428. X#endif
  1429. X        break;
  1430. X
  1431. X        case 'x':                           /* '\xFF'               */
  1432. X        count = 3;
  1433. X        value = 0;
  1434. X        while ((((c = get()) >= '0' && c <= '9')
  1435. X             || (c >= 'a' && c <= 'f')
  1436. X             || (c >= 'A' && c <= 'F'))
  1437. X            && (--count >= 0)) {
  1438. X            value *= 16;
  1439. X            value += (c <= '9') ? (c - '0') : ((c & 0xF) + 9);
  1440. X        }
  1441. X        unget();
  1442. X        break;
  1443. X
  1444. X        default:
  1445. X        if (c >= '0' && c <= '7') {
  1446. X            count = 3;
  1447. X            value = 0;
  1448. X            while (c >= '0' && c <= '7' && --count >= 0) {
  1449. X            value *= 8;
  1450. X            value += (c - '0');
  1451. X            c = get();
  1452. X            }
  1453. X            unget();
  1454. X        }
  1455. X        else value = c;
  1456. X        break;
  1457. X        }
  1458. X    }
  1459. X    else if (c == '\'')
  1460. X        value = 0;
  1461. X    else value = c;
  1462. X    /*
  1463. X     * We warn on multi-byte constants and try to hack
  1464. X     * (big|little)endian machines.
  1465. X     */
  1466. X#if BIG_ENDIAN
  1467. X    count = 0;
  1468. X#endif
  1469. X    while ((c = get()) != '\'' && c != EOF_CHAR && c != '\n') {
  1470. X        if (!skip)
  1471. X        ciwarn("multi-byte constant '%c' isn't portable", c);
  1472. X#if BIG_ENDIAN
  1473. X        count += BITS_CHAR;
  1474. X        value += (c << count);
  1475. X#else
  1476. X        value <<= BITS_CHAR;
  1477. X        value += c;
  1478. X#endif
  1479. X    }
  1480. X    instring = FALSE;
  1481. X    DBUG_RETURN (value);
  1482. X}
  1483. X
  1484. XFILE_LOCAL int *
  1485. Xevaleval(valp, op, skip)
  1486. Xregister int    *valp;
  1487. Xint        op;
  1488. Xint        skip;        /* TRUE if short-circuit evaluation    */
  1489. X/*
  1490. X * Apply the argument operator to the data on the value stack.
  1491. X * One or two values are popped from the value stack and the result
  1492. X * is pushed onto the value stack.
  1493. X *
  1494. X * OP_COL is a special case.
  1495. X *
  1496. X * evaleval() returns the new pointer to the top of the value stack.
  1497. X */
  1498. X{
  1499. X    register int    v1, v2;
  1500. X
  1501. X    DBUG_ENTER ("evaleval");
  1502. X    if (isbinary(op))
  1503. X        v2 = *--valp;
  1504. X    v1 = *--valp;
  1505. X#ifdef    DEBUG_EVAL
  1506. X    printf("%s op %s", (isbinary(op)) ? "binary" : "unary",
  1507. X        opname[op]);
  1508. X    if (isbinary(op))
  1509. X        printf(", v2 = %d.", v2);
  1510. X    printf(", v1 = %d.\n", v1);
  1511. X#endif
  1512. X    switch (op) {
  1513. X    case OP_EOE:
  1514. X         break;
  1515. X
  1516. X    case OP_ADD:
  1517. X        v1 += v2;
  1518. X        break;
  1519. X
  1520. X    case OP_SUB:
  1521. X        v1 -= v2;
  1522. X        break;
  1523. X
  1524. X    case OP_MUL:
  1525. X        v1 *= v2;
  1526. X        break;
  1527. X
  1528. X    case OP_DIV:
  1529. X    case OP_MOD:
  1530. X        if (v2 == 0) {
  1531. X        if (!skip) {
  1532. X            cwarn("%s by zero in #if, zero result assumed",
  1533. X            (op == OP_DIV) ? "divide" : "mod");
  1534. X        }
  1535. X        v1 = 0;
  1536. X        }
  1537. X        else if (op == OP_DIV)
  1538. X        v1 /= v2;
  1539. X        else
  1540. X        v1 %= v2;
  1541. X        break;
  1542. X
  1543. X    case OP_ASL:
  1544. X        v1 <<= v2;
  1545. X        break;
  1546. X
  1547. X    case OP_ASR:
  1548. X        v1 >>= v2;
  1549. X        break;
  1550. X
  1551. X    case OP_AND:
  1552. X        v1 &= v2;
  1553. X        break;
  1554. X
  1555. X    case OP_OR:
  1556. X        v1 |= v2;
  1557. X        break;
  1558. X
  1559. X    case OP_XOR:
  1560. X        v1 ^= v2;
  1561. X        break;
  1562. X
  1563. X    case OP_EQ:
  1564. X        v1 = (v1 == v2);
  1565. X        break;
  1566. X
  1567. X    case OP_NE:
  1568. X        v1 = (v1 != v2);
  1569. X        break;
  1570. X
  1571. X    case OP_LT:
  1572. X        v1 = (v1 < v2);
  1573. X        break;
  1574. X
  1575. X    case OP_LE:
  1576. X        v1 = (v1 <= v2);
  1577. X        break;
  1578. X
  1579. X    case OP_GE:
  1580. X        v1 = (v1 >= v2);
  1581. X        break;
  1582. X
  1583. X    case OP_GT:
  1584. X        v1 = (v1 > v2);
  1585. X        break;
  1586. X
  1587. X    case OP_ANA:
  1588. X        v1 = (v1 && v2);
  1589. X        break;
  1590. X
  1591. X    case OP_ORO:
  1592. X        v1 = (v1 || v2);
  1593. X        break;
  1594. X
  1595. X    case OP_COL:
  1596. X        /*
  1597. X         * v1 has the "true" value, v2 the "false" value.
  1598. X         * The top of the value stack has the test.
  1599. X         */
  1600. X        v1 = (*--valp) ? v1 : v2;
  1601. X        break;
  1602. X
  1603. X    case OP_NEG:
  1604. X        v1 = (-v1);
  1605. X        break;
  1606. X
  1607. X    case OP_PLU:
  1608. X        break;
  1609. X
  1610. X    case OP_COM:
  1611. X        v1 = ~v1;
  1612. X        break;
  1613. X
  1614. X    case OP_NOT:
  1615. X        v1 = !v1;
  1616. X        break;
  1617. X
  1618. X    default:
  1619. X        cierror("#if bug, operand = %d.", op);
  1620. X        v1 = 0;
  1621. X    }
  1622. X    *valp++ = v1;
  1623. X    DBUG_RETURN (valp);
  1624. X}
  1625. X
  1626. X#ifdef    DEBUG_EVAL
  1627. Xdumpstack(opstack, opp, value, valp)
  1628. XOPTAB        opstack[NEXP];    /* Operand stack        */
  1629. Xregister OPTAB    *opp;        /* Operator stack        */
  1630. Xint        value[NEXP];    /* Value stack            */
  1631. Xregister int    *valp;        /* -> value vector        */
  1632. X{
  1633. X    DBUG_ENTER ("dumpstack");
  1634. X    printf("index op prec skip name -- op stack at %s", infile->bptr);
  1635. X    while (opp > opstack) {
  1636. X        printf(" [%2d] %2d  %03o    %d %s\n", opp - opstack,
  1637. X        opp->op, opp->prec, opp->skip, opname[opp->op]);
  1638. X        opp--;
  1639. X    }
  1640. X    while (--valp >= value) {
  1641. X        printf("value[%d] = %d\n", (valp - value), *valp);
  1642. X    }
  1643. X    DBUG_VOID_RETURN;
  1644. X}
  1645. X#endif
  1646. X
  1647. END_OF_FILE
  1648. if test 23086 -ne `wc -c <'cpp5.c'`; then
  1649.     echo shar: \"'cpp5.c'\" unpacked with wrong size!
  1650. fi
  1651. # end of 'cpp5.c'
  1652. fi
  1653. echo shar: End of archive 3 \(of 5\).
  1654. cp /dev/null ark3isdone
  1655. MISSING=""
  1656. for I in 1 2 3 4 5 ; do
  1657.     if test ! -f ark${I}isdone ; then
  1658.     MISSING="${MISSING} ${I}"
  1659.     fi
  1660. done
  1661. if test "${MISSING}" = "" ; then
  1662.     echo You have unpacked all 5 archives.
  1663.     rm -f ark[1-9]isdone
  1664. else
  1665.     echo You still need to unpack the following archives:
  1666.     echo "        " ${MISSING}
  1667. fi
  1668. ##  End of shell archive.
  1669. exit 0
  1670. -- 
  1671. Submissions to comp.sources.amiga and comp.binaries.amiga should be sent to:
  1672.     amiga@cs.odu.edu    
  1673. or    amiga@xanth.cs.odu.edu    ( obsolescent mailers may need this address )
  1674. or    ...!uunet!xanth!amiga    ( very obsolescent mailers need this address )
  1675.  
  1676. Comments, questions, and suggestions s should be addressed to ``amiga-request''
  1677. (only use ``amiga'' for submissions) at the above addresses.
  1678.